unit GPIO;

{$mode objfpc}{$H+}
{$modeswitch advancedrecords}
{$SCOPEDENUMS ON}
{$IF DEFINED(DEBUG) or DEFINED(DEBUG_GPIO)}
  {$L gpio.c-debug.obj}
{$ELSE}
  {$L gpio.c.obj}
{$ENDIF}

interface

uses HAL;

type
  TDIR = (INPUT, OUTPUT);
  TPULL = (NONE, UP, DOWN);

  CGPIO = class
  protected
    FPIN: TPIN;
    FBits: DWord;

    procedure SetDir(Dir: TDIR);
    procedure SetPull(Pull: TPULL);
    function GetLevel: Boolean;
    procedure SetLevel(Level: Boolean);

  public
    constructor Create(PINx: TPIN);
    destructor Destroy; override;

  public
    property Dir: TDIR write SetDir;
    property Pull: TPULL write SetPull;
    property Value: Boolean read GetLevel write SetLevel;

  end;

implementation

  procedure gpio_init(Pin: TPIN); cdecl; external;
  procedure gpio_set_pulls(Pin: TPIN; const UP, DOWN: Boolean); cdecl; external;

constructor CGPIO.Create(PINx: TPIN);
begin
  inherited Create;

  FPIN:= PINx;
  FBits:= (1 shl PINx);

  gpio_init(PINx);
end;

destructor CGPIO.Destroy;
begin
  CHW.Release(Self);
  inherited Destroy;
end;

procedure CGPIO.SetDir(Dir: TDIR);
begin
  if (Dir = TDIR.INPUT) then
    sio.gpio_oe_clr:= FBits
  else
    sio.gpio_oe_set:= FBits;
end;

procedure CGPIO.SetPull(Pull: TPULL);
begin
  case (Pull) of
  TPULL.NONE: gpio_set_pulls(FPIN, False, False);
  TPULL.UP:   gpio_set_pulls(FPIN, True, False);
  TPULL.DOWN: gpio_set_pulls(FPIN, False, True);
  end;
end;

function CGPIO.GetLevel: Boolean;
begin
  Result:= ((SIO.gpio_in and FBits) <> 0);
end;

procedure CGPIO.SetLevel(Level: Boolean);
begin
  if (Level) then
    SIO.gpio_set:= FBits
  else
    SIO.gpio_clr:= FBits;
end;

end.

